package dog.network;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.sql.Timestamp;

import javax.swing.JOptionPane;

import constants.PROTOCOL;

import dog.model.Model;

public class Client extends Thread
	{
	Socket socket;
	private ClientParser parser;
	private DataInputStream input;
	private DataOutputStream output;
	private boolean connectionEstablished;
	private boolean isRunning;
	private String parseString;
	private boolean buildingParseString;
	@SuppressWarnings("unused")
	private Model model;
	
		
	public Client(Model model,String ip)
		{
		super();
		this.model=model;
		parseString="";
		buildingParseString=false;
		isRunning=true;
		parser = new ClientParser(this,model);
		
		try
			{
			socket = new Socket(ip, 1337);
			input=new DataInputStream(socket.getInputStream());
			output = new DataOutputStream(socket.getOutputStream());
			System.out.println("Client Socket (remote port "+socket.getPort()+") connected");
			connectionEstablished=true;
			}
		catch (ConnectException e)
			{
			model.serverDisconnected(false);
			System.out.println("Could not connect to the server!");
			connectionEstablished=false;
			}
		catch (UnknownHostException e)
			{
			model.serverDisconnected(false);
			System.out.println("Could not connect to the server!");
			connectionEstablished=false;
			}
		catch (IOException e)
			{
			e.printStackTrace();
			}
		start();
		}
	public void send(String s)
		{
		if(connectionEstablished)
			{
			int i=0;
			boolean fail=false;
			while(i<s.length() && !fail)
				{
				try {
					output.write((int) s.charAt(i));
					i++;
					}
				catch (SocketException e)
					{
					fail=true;
					closeSocket();
					connectionEstablished=false;
					model.serverDisconnected(true);
					System.out.println("The connection died(sending)");
					}
				catch (IOException e)
					{e.printStackTrace();}
				}
			}
		}

	public void run()
		{
		while (isRunning)
			{
			try
				{
				int  i= input.read();
				if(i==-1)
					{System.out.println("The server closed the socket");
					closeSocket();
					model.serverDisconnected(true);
					}
				else
					{
					char c= (char)i;
					if(c=='<' && !buildingParseString)
						buildingParseString=true;
					else if (c=='>' && buildingParseString)
						{
						parse(parseString);
						parseString="";
						buildingParseString=false;
						}
					else if (c!='<' && c!='>' && buildingParseString)
						parseString+=c;
					else
						System.out.println("spam: "+c);
					}
				}
			catch (SocketException e)
				{System.out.println("The connection died(receiving)");
				closeSocket();
				model.serverDisconnected(true);}
			catch (IOException e)
				{e.printStackTrace();}
			}
		}
	
	public void parse(String str)
		{
		parser.parse(str);
		}

	public void closeSocket()
		{
		isRunning=false;
		if(connectionEstablished)
			{
			try
				{
				int i = socket.getPort();
				connectionEstablished=false;
				input.close();
				output.close();
				socket.close();
				System.out.println("Client Socket(remote port "+i+") closed");
				}
			catch (IOException e)
				{e.printStackTrace();}
			}
		}
	public void dispose()
		{
		closeSocket();
		}

	public void loginAttempt(String username, String password)
		{
		send("<"+PROTOCOL.LOGIN_ATTEMPT+'|'+username+'|'+password+">");
		}
	public void sendRoom(int roomID, String roomName, int roomSize)
		{
		send("<"+PROTOCOL.ROOM+'|'+roomID+'|'+roomName+'|'+roomSize+">");
		System.out.println("Room creation request sent.");
		}
	public void sendDepartment(int departmentID, String departmentName)
		{
		send("<"+PROTOCOL.DEPARTMENT+'|'+departmentID+'|'+departmentName+">");
		System.out.println("Department creation request sent.");
		}
	public void sendPerson(int personID, String email, String password, String realName, int departmentID)
		{
		send("<"+PROTOCOL.PERSON+'|'+personID+'|'+email+'|'+password+'|'+realName+'|'+departmentID+">");
		System.out.println("Person creation request sent.");
		}
	public void sendAppointment(int personID, int appointmentID, Timestamp startTime, Timestamp endTime, String subject, String description, int roomID, String locationName, int changedFromID)
		{
		send("<"+PROTOCOL.APPOINTMENT+"|"+personID+"|"+appointmentID+"|"+startTime.getTime()+"|"+endTime.getTime()+"|"+subject+"|"+description+"|"+roomID+"|"+locationName+"|-1|"+changedFromID+"|0>");
		System.out.println("Appointment sent!");
		}
	public void checkRoom(int roomID, Timestamp fromTime, Timestamp toTime, int ownerPersonID, int appointmentID)
		{
		send("<"+PROTOCOL.CHECK_ROOM+'|'+roomID+'|'+fromTime.getTime()+'|'+toTime.getTime()+'|'+ownerPersonID+'|'+appointmentID+">");
		System.out.println("Room availability requested for room "+roomID);
		}
	public void accessPerson(int personID)
		{
		send("<"+PROTOCOL.ACCESS_PERSON+'|'+personID+">");
		System.out.println("Appointments requested for person "+personID);
		}
	public void unsetPerson(int personID)
		{
		send("<"+PROTOCOL.UNSET_PERSON+'|'+personID+">");
		System.out.println("Access unset for person "+personID);
		}
	public void accessRange(Timestamp start,Timestamp end)
		{
		send("<"+PROTOCOL.ACCESS_RANGE+'|'+start.getTime()+'|'+end.getTime()+">");
		System.out.println("Appointments requested for new range");
		}
	public void sendAttendance(int participantID, int ownerID, int appointmentID, int type, String reason)
		{
		send("<"+PROTOCOL.SET_ATTENDANCE+'|'+ownerID+'|'+appointmentID+'|'+participantID+'|'+type+'|'+reason+">");
		System.out.println("Attendance setting request sent");
		}
	public void unsetSpecificAccess()
		{
		send("<"+PROTOCOL.UNSET_SPECIFIC+">");
		System.out.println("Specific access unset");
		}
	public void requestSpecificAppointment(int ownerID, int appointmentID)
		{
		send("<"+PROTOCOL.GET_APPOINTMENT+'|'+ownerID+'|'+appointmentID+">");
		System.out.println("Specific request sent");
		}
	public void cancelAppointment(int ownerID, int appointmentID, String reason)
		{
		send("<"+PROTOCOL.DEL_APPOINTMENT+'|'+ownerID+'|'+appointmentID+'|'+reason+">");
		System.out.println("Appointment cancelling request sent");
		}
	public void deleteMessage(int personID, int messageID)
		{
		send("<"+PROTOCOL.DEL_MESSAGE+'|'+personID+'|'+messageID+">");
		System.out.println("Message deletion sent");
		}
	}